package request

import (
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
	"go.getaway.adminspro.padmins.com/untils"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
)

type RequestInterface interface {
	Params(a ...string) interface{}
	ParamsToString(key string, def ...string) string
	Ip() string
	Method() string
	Header(key string) string
	Cookie(name string) string
}

type Request struct {
	httpRequest *http.Request
	params      map[string]interface{}
}

func NewRequest(r *http.Request) RequestInterface {
	return &Request{
		httpRequest: r,
	}
}

func (req *Request) Params(a ...string) interface{} {

	if req.params == nil {

		req.params = map[string]interface{}{}

		_ = req.httpRequest.ParseForm()

		for k, v := range req.httpRequest.Form {
			k = strings.TrimRight(k, "[]")
			if len(v) > 1 {
				req.params[k] = v
			} else {
				req.params[k] = v[0]
			}
		}

		body, _ := ioutil.ReadAll(req.httpRequest.Body)
		_ = json.Unmarshal(body, &req.params)
	}

	key := ""
	def := ""
	switch len(a) {
	case 0:
		return req.params
	case 1:
		key = a[0]
	default:
		key = a[0]
		def = a[1]
	}

	if val, ok := req.params[key]; ok {
		return val
	}

	return def
}

func (req *Request) ParamsToString(key string, def ...string) string {
	return fmt.Sprintf("%v", req.Params(append([]string{
		key,
	}, def...)...))
}

func (req Request) Ip() string {
	xForwardedFor := req.httpRequest.Header.Get("X-Forwarded-For")
	ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])
	if ip != "" {
		return ip
	}

	ip = strings.TrimSpace(req.httpRequest.Header.Get("X-Real-Ip"))
	if ip != "" {
		return ip
	}

	if ip, _, err := net.SplitHostPort(strings.TrimSpace(req.httpRequest.RemoteAddr)); err == nil {
		return ip
	}

	return ""
}

func (req Request) Method() string {
	return req.httpRequest.Method
}

func (req Request) Header(key string) string {
	return req.httpRequest.Header.Get(key)
}

func (req Request) Cookie(name string) string {
	cookie, e := req.httpRequest.Cookie(name)
	if e != nil {
		return ""
	}
	return cookie.Value
}

type FastHttpRequest struct {
	httpRequest *fasthttp.RequestCtx
	params      map[string]interface{}
}

func NewFastHttpRequest(r *fasthttp.RequestCtx) RequestInterface {
	return &FastHttpRequest{
		httpRequest: r,
	}
}

func (req *FastHttpRequest) Params(a ...string) interface{} {
	if req.params == nil {
		req.params = map[string]interface{}{}
		values := map[string][]string{}
		req.httpRequest.QueryArgs().VisitAll(func(key, value []byte) {
			k := string(key)
			if untils.MbSubStr(k, -2) == "[]" {
				k = strings.TrimRight(k, "[]")
				values[k] = append(values[k], string(value))
				req.params[k] = values[k]
			} else {
				req.params[k] = string(value)
			}
		})

		req.httpRequest.PostArgs().VisitAll(func(key, value []byte) {
			k := string(key)
			if untils.MbSubStr(k, -2) == "[]" {
				k = strings.TrimRight(k, "[]")
				values[k] = append(values[k], string(value))
				req.params[k] = values[k]
			} else {
				req.params[k] = string(value)
			}
		})

		_ = json.Unmarshal(req.httpRequest.PostBody(), &req.params)

	}

	key := ""
	def := ""
	switch len(a) {
	case 0:
		return req.params
	case 1:
		key = a[0]
	default:
		key = a[0]
		def = a[1]
	}

	if val, ok := req.params[key]; ok {
		return val
	}

	return def
}

func (req *FastHttpRequest) ParamsToString(key string, def ...string) string {
	return fmt.Sprintf("%v", req.Params(append([]string{
		key,
	}, def...)...))
}

func (req FastHttpRequest) Ip() string {
	xForwardedFor := string(req.httpRequest.Request.Header.Peek("X-Forwarded-For"))
	ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])
	if ip != "" {
		return ip
	}

	ip = strings.TrimSpace(string(req.httpRequest.Request.Header.Peek("X-Real-Ip")))
	if ip != "" {
		return ip
	}

	if ip, _, err := net.SplitHostPort(strings.TrimSpace(req.httpRequest.RemoteAddr().String())); err == nil {
		return ip
	}

	return ""
}

func (req FastHttpRequest) Method() string {
	return string(req.httpRequest.Request.Header.Method())
}

func (req FastHttpRequest) Header(key string) string {
	return string(req.httpRequest.Request.Header.Peek(key))
}

func (req FastHttpRequest) Cookie(name string) string {
	return string(req.httpRequest.Request.Header.Cookie(name))
}
